我們昨天定義好了不同的碰撞效果,今天要來實作部分效果邏輯。
這次會修改 角色
腳本。
在角色腳本中建立新的變數,暴露出我們希望的初始速度以及若進入 SLOW
狀態時的速度。
@export var slow_speed:float = 1
@export var base_speed:float = 5
var speed:float = base_speed
在角色場景根節點上建立三個計時器作為我們不同效果的持續時間使用,根據效果狀態重新命名並修改右邊屬性值,開啟one_shot
、調整時間長度。
宣告這三個計時器,並在初始化時將剛剛建立的計時器連結到腳本上,同時將計時器的訊號
連結到各自的方法上,這些方法我們在下一步實作。
var invincible_timer:Timer
var slow_timer:Timer
var stop_timer:Timer
func _ready():
# <...> 之前的程式碼略過
# 新增下面程式碼。
invincible_timer = $"../InvincibleTimer"
invincible_timer.timeout.connect(_on_invincible_timeout)
slow_timer = $"../SlowTimer"
slow_timer.timeout.connect(_on_slow_timeout)
stop_timer = $"../StopTimer"
stop_timer.timeout.connect(_on_stop_timeout)
建立我們不同狀態時需要產生對應的效果
func handle_invincible_state():
get_node("CollisionShape2D").disabled = true
speed = base_speed
invincible_timer.start()
func _on_invincible_timeout():
get_node("CollisionShape2D").disabled = false
func handle_slow_state():
speed = slow_speed
slow_timer.start()
func _on_slow_timeout():
speed = base_speed
func handle_stop_state():
speed = 0
stop_timer.start()
func _on_stop_timeout():
speed = base_speed
func handle_end_state():
pass
將狀態處理的方法放回昨天建立的狀態判斷中。
DEFAULT
字串宣告成常數,方便未來如果更改可以只更改變宣告數值,不用在程式碼中一一尋找。宣告完成後可以所有要用到的地方都更新成常數。const DEFAULT = "DEFAULT"
# 更新成常數
var state:String = DEFAULT
func handle_player_state():
match state:
DEFAULT:
pass
"INVINCIBLE":
handle_invincible_state()
"SLOW":
handle_slow_state()
"STOP":
handle_stop_state()
"END":
handle_end_state()
state = DEFAULT
最後我們根據不同狀態各自建立一個場景。
scenes
資料夾下建立新資料夾 obstacles
方便管理。碰撞效果
(INVINCIBLE, SLOW, STOP)、Polygon2D
顏色及碰撞範圍。完整檔案
extends CharacterBody2D
# CharacterBody2D
var direction:Vector2
var dragged:bool = false
var oriPos: Vector2
var player: CharacterBody2D
var player_anime: AnimatedSprite2D
# MovementUI
var movement_ui: Node2D
# Collision Handling
@export var slow_speed:float = 1
@export var base_speed:float = 5
var speed:float = base_speed
var invincible_timer:Timer
var slow_timer:Timer
var stop_timer:Timer
const DEFAULT = "DEFAULT"
var state:String = DEFAULT
# Called when the node enters the scene tree for the first time.
func _ready():
movement_ui = $"../MovementUI"
movement_ui.visible = false
player = $"."
player_anime = player.get_node("AnimatedSprite2D")
invincible_timer = $"../InvincibleTimer"
invincible_timer.timeout.connect(_on_invincible_timeout)
slow_timer = $"../SlowTimer"
slow_timer.timeout.connect(_on_slow_timeout)
stop_timer = $"../StopTimer"
stop_timer.timeout.connect(_on_stop_timeout)
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
if dragged:
player.position += direction*speed
handle_player_state()
func _input(event):
if event is InputEventScreenTouch:
if event.is_pressed():
oriPos = event.position
dragged = true
player_anime.play()
movement_ui.visible = true
movement_ui.position = event.position
elif event.is_released():
direction = Vector2.ZERO
dragged = false
player_anime.stop()
movement_ui.visible = false
if event is InputEventScreenDrag:
direction = (event.position - oriPos).normalized()
movement_ui.rotation = Vector2.UP.angle_to(direction)
if abs(direction.y) > abs(direction.x):
player_anime.animation = "default"
elif direction.x > 0:
player_anime.animation = "turn_right"
elif direction.x < 0:
player_anime.animation = "turn_left"
func handle_player_state():
match state:
DEFAULT:
pass
"INVINCIBLE":
handle_invincible_state()
"SLOW":
handle_slow_state()
"STOP":
handle_stop_state()
"END":
handle_end_state()
state = DEFAULT
func handle_invincible_state():
get_node("CollisionShape2D").disabled = true
speed = base_speed
invincible_timer.start()
func _on_invincible_timeout():
get_node("CollisionShape2D").disabled = false
func handle_slow_state():
speed = slow_speed
slow_timer.start()
func _on_slow_timeout():
speed = base_speed
func handle_stop_state():
speed = 0
stop_timer.start()
func _on_stop_timeout():
speed = base_speed
func handle_end_state():
pass
:)